#ifndef SINGLETON_H
#define SINGLETON_H

#include <string>

namespace Singleton
{
    const std::string SINGLETON_LOG_PREFIX = "=== ";

    void logAlreadyInitialised(const std::string& className);
    void logInitialising(const std::string& className);
    void logInitialised(const std::string& className);

    void logAlreadyCleanedUp(const std::string& className);
    void logCleaningUp(const std::string& className);
    void logCleanedUp(const std::string& className);

    void throwNotInitialised(const std::string& className);
}

// Semi-colons intentionally left out of macros
// to keep macro calls consistent. Ie you have to call them like any function:
// BEGIN_INITIALISATION("SomeClass");

#define BEGIN_INITIALISATION(className) \
if(initialised) { Singleton::logAlreadyInitialised(className); return; } \
Singleton::logInitialising(className)

#define END_INITIALISATION(className) \
initialised = true; Singleton::logInitialised(className)


#define BEGIN_CLEAN_UP(className) \
if(!initialised) { Singleton::logAlreadyCleanedUp(className); return; } \
initialised = false; Singleton::logCleaningUp(className)

#define END_CLEAN_UP(className) \
Singleton::logCleanedUp(className)


#define GET_INSTANCE(className) \
if(!initialised) Singleton::throwNotInitialised(className); \
return instance

#define GET_INSTANCE_PTR_AS_REF(className) \
if(!initialised) Singleton::throwNotInitialised(className); \
return *instance

#endif